﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Windows;
using System.Windows.Controls;
using BindableDataGrid.Data;
using SilveR.DataValidators;
using SilveR.GUIValidators;

namespace SilveR.Views.StatsViews
{
    public partial class UnpairedTTest : UserControl, IAnalysis
    {
        private UnpairedTTestVariables unpairedTTestVariables;

        public UnpairedTTest()
        {
            InitializeComponent();

            unpairedTTestVariables = new UnpairedTTestVariables();
            this.DataContext = unpairedTTestVariables;
        }

        private void Target_ItemDragCompleted(object sender, ItemDragEventArgs e)
        {
            //ensure that the available variables stay sorted...
            SortableObservableCollection<ColumnInfo> availableVariables = (SortableObservableCollection<ColumnInfo>)lstAvailableVariables.ItemsSource;
            availableVariables.Sort(new ColumnIndexComparer());

            //only enable the response transformation combo if there are items in it
            cboResponseTransformations.IsEnabled = !String.IsNullOrEmpty(unpairedTTestVariables.Response);
        }

        private void oneItem_DragOverOrDrop(object sender, Microsoft.Windows.DragEventArgs e)
        {
            ListBoxDragDropTarget target = (ListBoxDragDropTarget)sender;
            ListBox lstBox = (ListBox)target.Content;

            //only allow one item in this listbox
            if (lstBox.Items.Count == 1)
            {
                e.Effects = Microsoft.Windows.DragDropEffects.None;
                e.Handled = true;
            }
        }

        private void cboData_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            //refill the available variables box when the selected datahandler changes
            DataHandler dh = (DataHandler)cboData.SelectedItem;

            if (dh != null)
                unpairedTTestVariables.AvailableVariables = dh.GetVariableList();
        }

        #region IAnalysis Members

        public bool ValidateGUI()
        {
            List<ValidationResult> validationResult = new List<ValidationResult>();
            bool validatedOK = Validator.TryValidateObject(unpairedTTestVariables, new ValidationContext(unpairedTTestVariables, null, null), validationResult, true);

            if (!validatedOK)
            {
                ValidationMessagesWindow vmw = new ValidationMessagesWindow(validationResult);
                vmw.Show();
            }

            return validatedOK;
        }

        public event DataValidatedEventHandler DataValidated;

        public void ValidateData()
        {
            UnpairedTTestValidator uptv = new UnpairedTTestValidator(unpairedTTestVariables);
            bool result = uptv.Validate();

            if (uptv.WarningMessages.Count > 0)
            {
                ValidationMessagesWindow vmw = new ValidationMessagesWindow(uptv.WarningMessages);
                vmw.Closed += new EventHandler(vmw_Closed);
                vmw.Show();
            }
            else
            {
                if (DataValidated != null)
                    DataValidated(this, new DataValidatedEventArgs(result));
            }
        }

        private void vmw_Closed(object sender, EventArgs e)
        {
            ValidationMessagesWindow vmw = (ValidationMessagesWindow)sender;

            if (DataValidated != null)
                DataValidated(this, new DataValidatedEventArgs(vmw.DialogResult.Value));
        }



        public string[] ExportData()
        {
            DataTable dtNew = this.DataHandler.DataTable.Copy();
            dtNew.Name = "ExportData";

            //Get the response and treatment columns
            foreach (DataColumn col in this.DataHandler.DataTable.Columns)
            {
                if (unpairedTTestVariables.Response != col.ColumnName && unpairedTTestVariables.Treatment != col.ColumnName)
                {
                    dtNew.Columns.Remove(col);
                }
            }

            //if the response is blank then remove that row
            dtNew.RemoveBlankRow(unpairedTTestVariables.Response);

            //Now do transformations...
            dtNew.TransformColumn(unpairedTTestVariables.Response, unpairedTTestVariables.ResponseTransformation);

            //Finally, as numeric categorical variables get misinterpreted by r, we need to go through
            //each column and put them in quotes...
            if (dtNew.CheckIsNumeric(unpairedTTestVariables.Treatment))
            {
                foreach (DataRow row in dtNew.Rows)
                {
                    row[unpairedTTestVariables.Treatment] = "'" + row[unpairedTTestVariables.Treatment] + "'";
                }
            }

            //...and export them
            return dtNew.GetCSVArray();
        }

        public DataHandler DataHandler
        {
            get { return unpairedTTestVariables.SelectedDataHandler; }
        }

        public Dictionary<string, string> GetAnalysisArguments()
        {
            Dictionary<string, string> arguments = new Dictionary<string, string>();
            arguments.Add("Response", ArgumentConverters.ConvertIllegalChars(unpairedTTestVariables.Response));
            arguments.Add("ResponseTransformation", ArgumentConverters.ConvertIllegalChars(unpairedTTestVariables.ResponseTransformation));

            arguments.Add("Treatment", ArgumentConverters.ConvertIllegalChars(unpairedTTestVariables.Treatment));

            arguments.Add("Equal Variance Case", ArgumentConverters.GetYesOrNo(unpairedTTestVariables.EqualVarianceSelected));
            arguments.Add("Unequal Variance Case", ArgumentConverters.GetYesOrNo(unpairedTTestVariables.UnequalVarianceSelected));

            arguments.Add("Produce PR Plot", ArgumentConverters.GetYesOrNo(unpairedTTestVariables.PRPlotSelected));
            arguments.Add("Produce Normal Plot", ArgumentConverters.GetYesOrNo(unpairedTTestVariables.NormalPlotSelected));

            arguments.Add("Significance Level", unpairedTTestVariables.Significance);

            return arguments;
        }

        public string AnalysisName
        {
            get { return "Unpaired t-test"; }
        }

        public string ScriptName
        {
            get { return "Unpairedttest.R"; }
        }

        public void UpdateDataHandlers()
        {
            //remember the current data handler before updating the available variables so that it can be selected later...
            DataHandler currentDataHandler = unpairedTTestVariables.SelectedDataHandler;

            App app = (App)Application.Current;
            unpairedTTestVariables.AvailableDataHandlers = app.DataHandlers;

            //reselect the current handler (if any)
            unpairedTTestVariables.SelectedDataHandler = currentDataHandler;
        }

        #endregion
    }


    public class UnpairedTTestVariables : INotifyPropertyChanged
    {
        public UnpairedTTestVariables()
        {
            App app = (App)Application.Current;
            availableDataHandlers = app.DataHandlers;
        }

        private ObservableCollection<DataHandler> availableDataHandlers = new ObservableCollection<DataHandler>();
        public ObservableCollection<DataHandler> AvailableDataHandlers
        {
            get
            {
                return availableDataHandlers;
            }

            set
            {
                availableDataHandlers = value;
                NotifyPropertyChanged("AvailableDataHandlers");
            }
        }

        private DataHandler selectedDataHandler;
        public DataHandler SelectedDataHandler
        {
            get { return selectedDataHandler; }
            set
            {
                selectedDataHandler = value;
                NotifyPropertyChanged("SelectedDataHandler");
            }
        }

        private ObservableCollection<ColumnInfo> availableVariables = new ObservableCollection<ColumnInfo>();
        public ObservableCollection<ColumnInfo> AvailableVariables
        {
            get { return availableVariables; }
            set
            {
                availableVariables = value;
                NotifyPropertyChanged("AvailableVariables");
            }
        }

        private ObservableCollection<ColumnInfo> responseList = new ObservableCollection<ColumnInfo>();
        public ObservableCollection<ColumnInfo> ResponseList
        {
            get { return responseList; }
            set
            {
                responseList[0] = value[0];
                NotifyPropertyChanged("ResponseList");
            }
        }

        [CustomValidation(typeof(NonParametricsGUIValidator), "CheckStringVarSet")]
        [Display(Name = "Response")]
        public string Response
        {
            get
            {
                if (responseList.Count == 1)
                    return responseList[0].ColumnName;
                else
                    return null;
            }
        }

        private string responseTransformation = "None";
        public string ResponseTransformation
        {
            get { return responseTransformation; }
            set { responseTransformation = value; }
        }

        private List<string> transformationList = new List<string>() { "None", "Log10", "Loge", "Square Root", "ArcSine", "Rank" };
        public List<string> TransformationList
        {
            get { return transformationList; }
        }

        private ObservableCollection<ColumnInfo> treatmentList = new ObservableCollection<ColumnInfo>();
        public ObservableCollection<ColumnInfo> TreatmentList
        {
            get { return treatmentList; }
            set
            {
                treatmentList[0] = value[0];
                NotifyPropertyChanged("TreatmentList");
            }
        }

        [CustomValidation(typeof(NonParametricsGUIValidator), "CheckStringVarSet")]
        [Display(Name = "Treatment")]
        public string Treatment
        {
            get
            {
                if (treatmentList.Count == 1)
                    return treatmentList[0].ColumnName;
                else
                    return null;
            }
        }

        private string significance = "0.05";
        public string Significance
        {
            get { return significance; }
            set { significance = value; }
        }

        private List<string> significanceList = new List<string>() { "0.1", "0.05", "0.01", "0.001" };
        public List<string> SignificanceList
        {
            get { return significanceList; }
        }

        private bool unequalVarianceSelected;
        public bool UnequalVarianceSelected
        {
            get { return unequalVarianceSelected; }
            set { unequalVarianceSelected = value; }
        }

        private bool equalVarianceSelected = true;
        public bool EqualVarianceSelected
        {
            get { return equalVarianceSelected; }
            set { equalVarianceSelected = value; }
        }

        private bool prPlotSelected = true;
        public bool PRPlotSelected
        {
            get { return prPlotSelected; }
            set { prPlotSelected = value; }
        }

        private bool normalPlotSelected;
        public bool NormalPlotSelected
        {
            get { return normalPlotSelected; }
            set { normalPlotSelected = value; }
        }
        

        public event PropertyChangedEventHandler PropertyChanged;

        // NotifyPropertyChanged will raise the PropertyChanged event, passing the source property that is being updated.
        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}